﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace NewDevice.RS485
{
    /// <summary>
    /// 6路交流电压采集器控制类
    /// 提供基于Modbus协议的6路交流电压采集功能
    /// </summary>
    public class ZH_40061_14N1
    {
        #region 初始化设置指令

        //01 06 00 51 00 00 //设置波特率115200
        //短接DZ01 //主动上传使能
        //01 06 00 4F 00 04 //响应时间设置为20ms
        //电压值=读值*30(量程)/10000

        #endregion 初始化设置指令

        /// <summary>
        /// 串口通信对象
        /// </summary>
        private SerialPort _serialPort;

        /// <summary>
        /// 接收数据队列（线程安全）
        /// </summary>
        private ConcurrentQueue<byte[]> _dataQueue = new ConcurrentQueue<byte[]>();

        /// <summary>
        /// 寄存器历史值缓存（通道号 -> 历史值列表）
        /// </summary>
        private Dictionary<int, List<Int16>> _registerValues = new Dictionary<int, List<Int16>>();

        /// <summary>
        /// 上次接收到数据的时间
        /// </summary>
        private DateTime _lastDataReceivedTime = DateTime.MinValue;

        /// <summary>
        /// 通信超时时间（秒）
        /// </summary>
        private const int TimeoutSeconds = 5;

        /// <summary>
        /// 任务取消令牌源
        /// </summary>
        private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();

        /// <summary>
        /// 线程同步锁对象
        /// </summary>
        private readonly object _lock = new object();

        /// <summary>
        /// 通信异常事件
        /// </summary>
        public event Action<string> OnCommunicationError;

        /// <summary>
        /// 获取或设置每个寄存器的历史值列表的最大长度
        /// </summary>
        public int MaxHistorySize { get; set; } = 5000;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="portName">串口名称，默认为COM7</param>
        /// <param name="baudRate">波特率，默认为115200</param>
        public ZH_40061_14N1(string portName = "COM7", int baudRate = 115200)
        {
            _serialPort = new SerialPort(portName, baudRate);
        }

        /// <summary>
        /// 获取所有通道的电压历史值（已转换为实际电压值）
        /// </summary>
        /// <remarks>
        /// 电压值计算公式：读值*30(量程)/10000，并保留3位小数
        /// </remarks>
        public Dictionary<int, List<double>> RegisterValues
        {
            get
            {
                lock (_lock)
                {
                    return _registerValues.ToDictionary(
                        kvp => kvp.Key,
                        kvp => kvp.Value.Select(v => Math.Round(v * 30 / 10000.0, 3)).ToList()
                    );
                }
            }
        }

        /// <summary>
        /// 启动串口通信
        /// </summary>
        /// <returns>异步任务</returns>
        /// <exception cref="System.IO.IOException">串口打开失败时抛出</exception>
        public async Task StartAsync()
        {
            try
            {
                Console.WriteLine($"Opening serial port {_serialPort.PortName} at {_serialPort.BaudRate} baud...");
                _serialPort.Open();
                Console.WriteLine("Serial port opened.");

                _serialPort.DataReceived += SerialPort_DataReceived;

                var processTask = Task.Run(() => ProcessDataAsync(_cancellationTokenSource.Token));
                var timeoutTask = Task.Run(() => CheckForTimeoutAsync(_cancellationTokenSource.Token));

                await Task.WhenAll(processTask, timeoutTask);
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("StartAsync was canceled.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}");
                OnCommunicationError?.Invoke($"Error: {ex.Message}");
                throw;
            }
            finally
            {
                _serialPort?.Close();
                Console.WriteLine("Serial port closed.");
            }
        }

        /// <summary>
        /// 用于缓存不完整的数据包
        /// </summary>
        private byte[] _remainingData = Array.Empty<byte>();

        /// <summary>
        /// 串口数据接收事件处理
        /// </summary>
        /// <param name="sender">事件源</param>
        /// <param name="e">事件参数</param>
        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                int bytesToRead = _serialPort.BytesToRead;
                byte[] buffer = new byte[bytesToRead];
                _serialPort.Read(buffer, 0, bytesToRead);

                byte[] combinedData = new byte[_remainingData.Length + bytesToRead];
                Buffer.BlockCopy(_remainingData, 0, combinedData, 0, _remainingData.Length);
                Buffer.BlockCopy(buffer, 0, combinedData, _remainingData.Length, bytesToRead);

                int offset = 0;
                while (offset + 19 <= combinedData.Length) // 每组完整数据包长度为19字节
                {
                    if (combinedData[offset] == 0x01 && combinedData[offset + 1] == 0x03 && combinedData[offset + 2] == 0x0E)
                    {
                        byte[] dataPacket = new byte[19];
                        Buffer.BlockCopy(combinedData, offset, dataPacket, 0, 19);
                        _dataQueue.Enqueue(dataPacket);
                        offset += 19;
                    }
                    else
                    {
                        offset++;
                    }
                }

                _remainingData = new byte[combinedData.Length - offset];
                Buffer.BlockCopy(combinedData, offset, _remainingData, 0, _remainingData.Length);

                _lastDataReceivedTime = DateTime.Now;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error receiving data: {ex.Message}");
                OnCommunicationError?.Invoke($"Error receiving data: {ex.Message}");
            }
        }

        /// <summary>
        /// 数据处理任务
        /// </summary>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>异步任务</returns>
        private async Task ProcessDataAsync(CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                try
                {
                    if (_dataQueue.TryDequeue(out byte[] data))
                    {
                        ParseReceivedData(data);
                    }
                    else
                    {
                        await Task.Delay(10, cancellationToken);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error processing data: {ex.Message}");
                    OnCommunicationError?.Invoke($"Error processing data: {ex.Message}");
                }
            }
        }

        /// <summary>
        /// 超时检测任务
        /// </summary>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>异步任务</returns>
        private async Task CheckForTimeoutAsync(CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                await Task.Delay(1000);

                if ((DateTime.Now - _lastDataReceivedTime).TotalSeconds > TimeoutSeconds)
                {
                    OnCommunicationError?.Invoke("No data received for a long time. Communication may be interrupted.");
                    _lastDataReceivedTime = DateTime.Now;
                }
            }
        }

        /// <summary>
        /// 解析接收到的Modbus数据包
        /// </summary>
        /// <param name="data">接收到的数据</param>
        private void ParseReceivedData(byte[] data)
        {
            lock (_lock)
            {
                if (data.Length < 5) return;

                byte address = data[0];
                byte opCode = data[1];
                byte dataLength = data[2];

                if (data.Length < 3 + dataLength + 2) return;

                byte[] registerData = new byte[dataLength];
                Array.Copy(data, 3, registerData, 0, dataLength);

                ParseRegisterValues(registerData);
            }
        }

        /// <summary>
        /// 解析寄存器值并更新缓存
        /// </summary>
        /// <param name="data">寄存器数据</param>
        private void ParseRegisterValues(byte[] data)
        {
            lock (_lock)
            {
                for (int i = 0; i < data.Length; i += 2)
                {
                    if (i + 1 >= data.Length) break;

                    int registerAddress = i / 2;
                    Int16 registerValue = (Int16)((data[i] << 8) | data[i + 1]);

                    if (!_registerValues.ContainsKey(registerAddress))
                    {
                        _registerValues[registerAddress] = new List<Int16>();
                    }

                    var registerHistory = _registerValues[registerAddress];
                    registerHistory.Add(registerValue);

                    if (registerHistory.Count > MaxHistorySize)
                    {
                        registerHistory.RemoveAt(0);
                    }
                }
            }
        }

        /// <summary>
        /// 获取指定通道的当前电压原始值
        /// </summary>
        /// <param name="registerAddress">通道地址(0-5)</param>
        /// <returns>当前电压原始值</returns>
        public Int16 GetRegisterValue(int registerAddress)
        {
            lock (_lock)
            {
                if (_registerValues.TryGetValue(registerAddress, out List<Int16> values) && values.Count > 0)
                {
                    return values.Last();
                }
                else
                {
                    Console.WriteLine($"Register {registerAddress} not found. Returning default value 0.");
                    return 0;
                }
            }
        }

        /// <summary>
        /// 获取指定通道的所有历史电压原始值
        /// </summary>
        /// <param name="registerAddress">通道地址(0-5)</param>
        /// <returns>历史电压原始值列表</returns>
        public List<Int16> GetRegisterHistory(int registerAddress)
        {
            lock (_lock)
            {
                if (_registerValues.TryGetValue(registerAddress, out List<Int16> values))
                {
                    return values.ToList();
                }
                else
                {
                    Console.WriteLine($"Register {registerAddress} not found. Returning empty list.");
                    return new List<Int16>();
                }
            }
        }

        /// <summary>
        /// 清空所有通道的历史数据缓存
        /// </summary>
        public void ClearRegisterValues()
        {
            lock (_lock)
            {
                _registerValues.Clear();
                Console.WriteLine("Register values cache cleared.");
            }
        }

        /// <summary>
        /// 断开串口连接并停止所有任务
        /// </summary>
        public void Disconnect()
        {
            _cancellationTokenSource.Cancel();
            _serialPort?.Close();
            Console.WriteLine("Serial port closed.");
        }
    }
}